package com.cory.utils.file;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * 文件上传工具类
 */
public class UploadUtils {
	//定义最大文件大小（10M）
	private static long MAX_SIZE = 1024 * 1024 * 10;
	// 定义允许上传的文件扩展名
	private static Map<Integer, String> EXT_MAP = new HashMap<Integer, String>();
	
	private static String TEM_PATH = System.getProperty("java.io.tmpdir");
	
	private static int IMAGE = 1;
	private static int FLASH = 2;
	private static int MEDIAS = 3;
	private static int FILE = 4;
	
	static {
		EXT_MAP.put(IMAGE, "gif,jpg,jpeg,png,bmp");
		EXT_MAP.put(FLASH, "swf,flv");
		EXT_MAP.put(MEDIAS, "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
		EXT_MAP.put(FILE, "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2");
	}
	
	public static List<String> uploadFile(HttpServletRequest request, String savePath) throws Exception {
		return uploadFile(request, savePath, "", MAX_SIZE);
	}

	public static List<String> uploadFile(HttpServletRequest request, String savePath, Integer FileType) throws Exception {
		return uploadFile(request, savePath, FileType, MAX_SIZE);
	}
	
	public static List<String> uploadFile(HttpServletRequest request, String savePath, Integer FileType, Long maxSize) throws Exception {
		if(FileType != null)
			return uploadFile(request, savePath, EXT_MAP.get(FileType), maxSize);
		return uploadFile(request, savePath, "", maxSize);
	}
	
	/**
	 * 文件上传
	 * savePath 文件保存目录
	 * extTypes 文件限制扩展名（已,分隔）
	 * maxSize 文件最大大小
	 * return 文件名列表（已;分隔）
	 */
	public static List<String> uploadFile(HttpServletRequest request, String savePath, String extTypes, Long maxSize) throws Exception {
		if(maxSize == null)	 maxSize = MAX_SIZE;
		
		validate(request, savePath);
		
		List<FileItem> items = initFields(request);
		
		List<String> fileNames = new ArrayList<String>();
		if(items != null && items.size() > 0) {
			for (FileItem item : items) {
				validateFile(item, extTypes, maxSize);
			}
			for (FileItem item : items) {
				fileNames.add(saveFile(item, savePath));
			}
		}
		
		return fileNames;
	}
	
	private static void validate(HttpServletRequest request, String savePath) {
		String contentType = request.getContentType();
		File uploadDir = new File(savePath);
		
		if (contentType == null || !contentType.startsWith("multipart")) {
			throw new RuntimeException("请求不包含multipart/form-data流");
		} else if (!ServletFileUpload.isMultipartContent(request)) {
			throw new RuntimeException("请选择文件");
		} else if (uploadDir.exists() && !uploadDir.canWrite()) {
			throw new RuntimeException("上传目录[" + savePath + "]没有写权限");
		} else if(!uploadDir.exists()) {
			uploadDir.mkdirs();
		}
	}
	
	private static List<FileItem> initFields(HttpServletRequest request) throws FileUploadException {
		DiskFileItemFactory factory = new DiskFileItemFactory();
		
		// 阀值,超过这个值才会写到临时目录,否则在内存中
		factory.setSizeThreshold(1024 * 1024 * 10);
		factory.setRepository(new File(TEM_PATH));
		
		ServletFileUpload upload = new ServletFileUpload(factory);
		upload.setHeaderEncoding("UTF-8");
		
		List<FileItem> items = upload.parseRequest(request);
		if(items != null && items.size() > 0) {
			Iterator<FileItem> iter = items.iterator();
			List<FileItem> fields = new ArrayList<FileItem>();
			
			while (iter.hasNext()) {
				FileItem item = iter.next();
				if (!item.isFormField()) {
					fields.add(item);
				} 
				return fields;
			}
		}
		return null;
	}
	
	private static void validateFile(FileItem item, String extTypes, long maxSize) {
		if (item.getSize() > maxSize) {
			throw new RuntimeException("上传文件大小超过限制");
		}
		
		if(extTypes != null && extTypes.length() > 0) {
			String fileName = item.getName();
			String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
			if(!Arrays.<String> asList(extTypes.split(",")).contains(fileExt))
				throw new RuntimeException("上传文件扩展名是不允许的扩展名");
		}
	}
	
	private static String saveFile(FileItem item, String savePath) throws Exception{
		String fileName = item.getName();
		String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
		
		String newFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;
		
		File uploadedFile = new File(savePath, newFileName);
		item.write(uploadedFile);
		
		return newFileName;
	}
}
